﻿#region File and License Information
/*
<File>
	<License>
		Copyright © 2009 - 2017, Daniel Vaughan. All rights reserved.
		This file is part of Calcium (http://calciumsdk.net), 
		which is released under the MIT License.
		See file /Documentation/License.txt for details.
	</License>
	<CreationDate>2015-04-25 18:20:18Z</CreationDate>
</File>
*/
#endregion

using System;
using System.Xml.Linq;

using Outcoder.Data.Serialization;
using Outcoder.Services;

namespace Outcoder.Data.Settings
{
	/// <summary>
	/// This class allows you to convert an object to an XML representation, 
	/// which is useful for storing settings with a particular storage location. 
	/// <seealso cref="StorageLocation"/>
	/// </summary>
	public class SerializableSetting : IXmlConvertible
	{
		const int formatVersion = 1;
		const string formatVersionElementName = "ClassVersion";
		const string elementValueName = "Value";
		const string elementStorageLocationName = "StorageLocation";
		const string elementOptionName = "Setting";
		const string elementNameName = "Name";

		public SerializableSetting()
		{
			/* Intentionally left blank. */
		}

		public SerializableSetting(string name, object settingValue, StorageLocation? storageLocation)
		{
			Name = ArgumentValidator.AssertNotNull(name, "name");
			SettingValue = settingValue;
			StorageLocation = storageLocation;
		}

		public SerializableSetting(XElement element)
		{
			ArgumentValidator.AssertNotNull(element, "element");

			FromXElementCore(element);
		}

		void IXmlConvertible.FromXElement(XElement element)
		{
			ArgumentValidator.AssertNotNull(element, "element");

			FromXElementCore(element);
		}

		void FromXElementCore(XElement element)
		{
			var rootElement = element.Element(elementOptionName);
			if (rootElement == null)
			{
				rootElement = element;
			}

			var version = (int)rootElement.Element(formatVersionElementName);

			Name = (string)rootElement.Element(elementNameName);

			var storageLocationElement = rootElement.Element(elementStorageLocationName);

			if (storageLocationElement != null)
			{
				string storageLocationString = storageLocationElement.Value;
				if (!string.IsNullOrWhiteSpace(storageLocationString))
				{
					StorageLocation parsedValue;
					try
					{
						parsedValue = (StorageLocation)Enum.Parse(typeof(StorageLocation), storageLocationString);
					}
					catch (Exception ex)
					{
						throw new FormatException("StorageLocation element has invalid value of " + storageLocationString, ex);
					}

					StorageLocation = parsedValue;
				}
			}

			var settingValueElement = rootElement.Element(elementValueName);

			if (settingValueElement != null)
			{
				try
				{
					var base64String = settingValueElement.Value;
					byte[] bytes = Convert.FromBase64String(base64String);
					var originalObject = SilverlightSerializer.Deserialize(bytes);
					SettingValue = originalObject;
				}
				catch (Exception ex)
				{
					throw new FormatException(elementValueName + " was unable to be parsed from base64 string.", ex);
				}
			}

			if (version > 1)
			{

			}
		}

		public XElement ToXElement()
		{
			XElement element = new XElement(elementOptionName,
				new XElement(formatVersionElementName, formatVersion),
				new XElement(elementNameName, Name)
				);

			if (StorageLocation.HasValue)
			{
				element.Add(new XElement(elementStorageLocationName, StorageLocation));
			}

			var objectToSerialize = SettingValue;
			if (objectToSerialize != null)
			{
				byte[] bytes = SilverlightSerializer.Serialize(objectToSerialize);
				string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
				XElement valueElement = new XElement(elementValueName, base64String);
				element.Add(valueElement);
			}

			return element;
		}

		public string Name { get; set; }

		public StorageLocation? StorageLocation { get; set; }

		public object SettingValue { get; set; }
	}
}